using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using RestaurantFinder.Core.Models;
using RestaurantFinder.Core.Services;
using System.Collections.Concurrent;

namespace RestaurantFinder.Infrastructure.Services;

/// <summary>
/// 基于内存的搜索缓存服务实现
/// </summary>
public class MemorySearchCacheService : ISearchCacheService
{
    private readonly IMemoryCache _memoryCache;
    private readonly ILogger<MemorySearchCacheService> _logger;
    private readonly CacheSettings _cacheSettings;
    
    // 缓存统计信息
    private readonly ConcurrentDictionary<string, DateTime> _cacheKeys = new();
    private long _hitCount = 0;
    private long _missCount = 0;

    public MemorySearchCacheService(
        IMemoryCache memoryCache,
        IConfiguration configuration,
        ILogger<MemorySearchCacheService> logger)
    {
        _memoryCache = memoryCache;
        _logger = logger;
        
        // 从配置中读取缓存设置
        _cacheSettings = new CacheSettings();
        configuration.GetSection("Cache").Bind(_cacheSettings);

        _logger.LogInformation("🗃️ 搜索缓存服务已初始化 - 启用: {Enabled}, 过期时间: {ExpirationMinutes}分钟, 最大条目: {MaxSize}", 
            _cacheSettings.SearchCacheEnabled, 
            _cacheSettings.SearchCacheExpirationMinutes,
            _cacheSettings.MaxCacheSize);
    }

    /// <summary>
    /// 获取缓存的搜索结果
    /// </summary>
    public async Task<List<Restaurant>?> GetCachedSearchResultAsync(Location location, int radiusInMeters, string? category = null)
    {
        if (!_cacheSettings.SearchCacheEnabled)
        {
            return null;
        }

        try
        {
            var cacheKey = new SearchCacheKey(location, radiusInMeters, category);
            var cacheKeyString = cacheKey.ToString();

            if (_memoryCache.TryGetValue(cacheKeyString, out List<Restaurant>? cachedRestaurants))
            {
                Interlocked.Increment(ref _hitCount);
                _logger.LogInformation("🎯 缓存命中: {CacheKey}, 返回 {Count} 家餐厅", cacheKeyString, cachedRestaurants?.Count ?? 0);
                return cachedRestaurants;
            }

            // 检查是否有相近位置的缓存
            var nearbyCache = await FindNearbyCacheAsync(location, radiusInMeters, category);
            if (nearbyCache != null)
            {
                Interlocked.Increment(ref _hitCount);
                _logger.LogDebug("🎯 附近缓存命中: {CacheKey}, 返回 {Count} 家餐厅", cacheKeyString, nearbyCache.Count);
                return nearbyCache;
            }

            Interlocked.Increment(ref _missCount);
            _logger.LogInformation("❌ 缓存未命中: {CacheKey}", cacheKeyString);
            return null;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "获取缓存时发生错误");
            return null;
        }
    }

    /// <summary>
    /// 缓存搜索结果
    /// </summary>
    public async Task SetCachedSearchResultAsync(Location location, int radiusInMeters, List<Restaurant> restaurants, string? category = null)
    {
        if (!_cacheSettings.SearchCacheEnabled)
        {
            return;
        }

        try
        {
            var cacheKey = new SearchCacheKey(location, radiusInMeters, category);
            var cacheKeyString = cacheKey.ToString();

            // 检查缓存大小限制
            await EnsureCacheSizeLimitAsync();

            // 设置缓存选项
            var cacheOptions = new MemoryCacheEntryOptions
            {
                AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(_cacheSettings.SearchCacheExpirationMinutes),
                Priority = CacheItemPriority.Normal,
                Size = EstimateSize(restaurants)
            };

            // 添加缓存移除回调
            cacheOptions.RegisterPostEvictionCallback((key, value, reason, state) =>
            {
                if (key is string keyString)
                {
                    _cacheKeys.TryRemove(keyString, out _);
                    _logger.LogInformation("🗑️ 缓存条目已移除: {Key}, 原因: {Reason}, 估算大小: {Size}字节", 
                        keyString, reason, EstimateSize((List<Restaurant>)value!));
                }
            });

            _memoryCache.Set(cacheKeyString, restaurants, cacheOptions);
            _cacheKeys[cacheKeyString] = DateTime.UtcNow;

            _logger.LogInformation("💾 已缓存搜索结果: {CacheKey}, 餐厅数量: {Count}, 估算大小: {Size}字节, 过期时间: {ExpirationMinutes}分钟", 
                cacheKeyString, restaurants.Count, EstimateSize(restaurants), _cacheSettings.SearchCacheExpirationMinutes);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "设置缓存时发生错误");
        }
    }

    /// <summary>
    /// 清除所有缓存
    /// </summary>
    public async Task ClearAllCacheAsync()
    {
        try
        {
            var keysToRemove = _cacheKeys.Keys.ToList();
            foreach (var key in keysToRemove)
            {
                _memoryCache.Remove(key);
            }
            _cacheKeys.Clear();

            _logger.LogInformation("🧹 已清除所有搜索缓存，共 {Count} 个条目", keysToRemove.Count);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "清除缓存时发生错误");
        }
    }

    /// <summary>
    /// 获取缓存统计信息
    /// </summary>
    public async Task<CacheStatistics> GetCacheStatisticsAsync()
    {
        try
        {
            var totalEntries = _cacheKeys.Count;
            var hitCount = Interlocked.Read(ref _hitCount);
            var missCount = Interlocked.Read(ref _missCount);
            
            // 估算内存使用量（简单估算）
            var estimatedMemoryUsage = totalEntries * 1024; // 假设每个条目平均1KB

            return new CacheStatistics
            {
                TotalEntries = totalEntries,
                HitCount = hitCount,
                MissCount = missCount,
                EstimatedMemoryUsage = estimatedMemoryUsage
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "获取缓存统计信息时发生错误");
            return new CacheStatistics();
        }
    }

    /// <summary>
    /// 查找附近的缓存
    /// </summary>
    private async Task<List<Restaurant>?> FindNearbyCacheAsync(Location location, int radiusInMeters, string? category)
    {
        try
        {
            foreach (var kvp in _cacheKeys)
            {
                var cacheKeyString = kvp.Key;
                
                // 解析缓存键以获取位置信息
                if (TryParseCacheKey(cacheKeyString, out var cachedLocation, out var cachedRadius, out var cachedCategory))
                {
                    // 检查类别是否匹配
                    if (category != cachedCategory)
                        continue;

                    // 检查半径是否匹配（允许一定误差）
                    if (Math.Abs(radiusInMeters - cachedRadius) > 500)
                        continue;

                    // 检查位置是否在容差范围内
                    var cacheKey = new SearchCacheKey(cachedLocation, cachedRadius, cachedCategory);
                    if (cacheKey.IsWithinTolerance(location, _cacheSettings.LocationToleranceMeters))
                    {
                        if (_memoryCache.TryGetValue(cacheKeyString, out List<Restaurant>? cachedRestaurants))
                        {
                            return cachedRestaurants;
                        }
                    }
                }
            }

            return null;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "查找附近缓存时发生错误");
            return null;
        }
    }

    /// <summary>
    /// 解析缓存键
    /// </summary>
    private bool TryParseCacheKey(string cacheKey, out Location location, out int radius, out string? category)
    {
        location = new Location(0, 0);
        radius = 0;
        category = null;

        try
        {
            // 格式: search_{lat}_{lng}_{radius}_{category}
            var parts = cacheKey.Split('_');
            if (parts.Length >= 4 && parts[0] == "search")
            {
                var lat = double.Parse(parts[1]);
                var lng = double.Parse(parts[2]);
                radius = int.Parse(parts[3]);
                category = parts.Length > 4 ? parts[4] : null;
                
                location = new Location(lat, lng);
                return true;
            }

            return false;
        }
        catch
        {
            return false;
        }
    }

    /// <summary>
    /// 确保缓存大小不超过限制
    /// </summary>
    private async Task EnsureCacheSizeLimitAsync()
    {
        if (_cacheKeys.Count >= _cacheSettings.MaxCacheSize)
        {
            // 移除最旧的缓存条目
            var oldestEntry = _cacheKeys.OrderBy(kvp => kvp.Value).FirstOrDefault();
            if (!string.IsNullOrEmpty(oldestEntry.Key))
            {
                _memoryCache.Remove(oldestEntry.Key);
                _cacheKeys.TryRemove(oldestEntry.Key, out _);
                _logger.LogDebug("🗑️ 移除最旧的缓存条目: {Key}", oldestEntry.Key);
            }
        }
    }

    /// <summary>
    /// 估算餐厅列表的内存大小（字节）
    /// </summary>
    private static int EstimateSize(List<Restaurant> restaurants)
    {
        // 更保守的估算：每个餐厅对象约50字节（减少估算值）
        var estimatedSize = restaurants.Count * 50;
        
        // 添加基础开销
        estimatedSize += 100; // 基础对象开销
        
        return estimatedSize;
    }
} 